package com.wg.game;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.game.app.BaseGameApplication;

import java.lang.reflect.Constructor;

/**
 * 游戏启动器（单例启动入口）
 * <p>
 * 职责：
 * - 提供统一的游戏应用启动入口，通过反射实例化并启动指定游戏应用
 * - 封装启动过程中的异常处理与日志记录，提升启动可靠性
 * - 校验启动参数合法性（含无参构造函数检查）
 *
 * @author 少爷123
 */
public final class Launcher {
    private static final Log log = LogFactory.get();

    /**
     * 私有构造（防止外部实例化）
     */
    private Launcher() {
    }

    /**
     * 启动游戏应用（核心入口方法）
     * <p>
     * 启动流程：
     * 1. 参数合法性校验（确保应用类不为空且包含无参构造函数）
     * 2. 反射实例化游戏应用（调用无参构造函数）
     * 3. 调用应用对象的 `start` 方法传递启动参数
     * 4. 全流程异常捕获与日志记录
     *
     * @param klass 游戏应用类（必须是 {@link BaseGameApplication} 的子类，且包含无参构造函数）
     * @param args  启动参数（可选，可为 null）
     * @throws GameLaunchException 启动失败时抛出（包含具体错误原因）
     */
    public static void run(Class<? extends BaseGameApplication> klass, String[] args) {
        validateLaunchParams(klass);

        log.info("开始启动游戏应用 | 应用类：{}", klass.getName());

        long startTime = System.currentTimeMillis();
        BaseGameApplication appInstance = null;

        try {
            appInstance = ReflectUtil.newInstance(klass);
            log.debug("游戏应用实例化成功 | 应用类：{}", klass.getName());

            appInstance.start(args);
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("游戏应用启动失败 | 应用类：{}，耗时：{}ms，异常信息：{}",
                    klass.getName(), duration, e.getMessage(), e);
            throw new GameLaunchException("游戏启动失败：" + e.getMessage(), e, klass.getName(), duration);
        }
    }

    /**
     * 校验启动参数合法性（含无参构造函数检查）
     *
     * @param klass 游戏应用类
     */
    private static void validateLaunchParams(Class<? extends BaseGameApplication> klass) {
        if (klass == null) {
            log.error("启动参数非法：游戏应用类不能为 null");
            throw new IllegalArgumentException("游戏应用类不能为 null");
        }

        if (!BaseGameApplication.class.isAssignableFrom(klass)) {
            log.error("启动参数非法：游戏应用类 [{}] 未继承自 BaseGameApplication", klass.getName());
            throw new IllegalArgumentException("游戏应用类必须继承自 BaseGameApplication");
        }

        boolean hasNoArgConstructor = checkNoArgConstructorExists(klass);
        if (!hasNoArgConstructor) {
            log.error("启动参数非法：游戏应用类 [{}] 缺少无参构造函数", klass.getName());
            throw new IllegalArgumentException("游戏应用类必须包含无参构造函数（无参数）");
        }
    }

    /**
     * 检查类是否存在无参构造函数（包括公共/私有）
     *
     * @param klass 目标类
     * @return 存在无参构造函数返回 true，否则 false
     */
    private static boolean checkNoArgConstructorExists(Class<?> klass) {
        Constructor<?>[] constructors = klass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            if (constructor.getParameterCount() == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 自定义游戏启动异常类（封装启动失败的上下文信息）
     */
    public static class GameLaunchException extends RuntimeException {
        private final String appName; // 应用类名
        private final long costMs; // 启动耗时（ms）

        public GameLaunchException(String message, Throwable cause, String appName, long costMs) {
            super(message, cause);
            this.appName = appName;
            this.costMs = costMs;
        }

        public String getAppName() {
            return appName;
        }

        public long getCostMs() {
            return costMs;
        }
    }
}